/**
 * 
 */
package com.ofek.eventos.net.lks;

import java.util.ArrayList;




/**
 * 
 * @author Ofek
 *
 * @param <IDT> id type
 * @param <IT> item type
 */
public class DistributedDatabase<IDT,IT> {
	protected final IDistributeableDatabaseHandle<IDT,IT> dbhandle;
	protected final LastKnownSyncer<IDT, IT> lastKnownSyncer;

	private final String name;
	/**
	 * handle should not be used directly if one wants this class to operate as expected
	 */
	public DistributedDatabase(final String name,final IDistributeableDatabaseHandle<IDT,IT> databaseHandle,final ISyncer<IDT,IT> syncerOut) {
		dbhandle = databaseHandle;
		lastKnownSyncer = new LastKnownSyncer<IDT,IT>(name,dbhandle,syncerOut);
		this.name = name;
	}
	/**
	 * This requests the addition of t if not exists, otherwise t will be replacing the instance that has the same key, when t is added or updated all listeners will be notified
	 * notice : if this method invoked twice before last confirm, the later version of t is the one that will be used, the rest will be completely ignored.
	 * @param t
	 */
	public void initiateAddOrUpdate(final IDT id,final IT t) {
		try {
			dbhandle.lock();
			Long oldVersion = dbhandle.getVersion(id);
			if (oldVersion==null) 
				dbhandle.addChangePending(id,t,0);
			else {
				dbhandle.addChangePending(id,t,++oldVersion);
			}
		} finally {
			dbhandle.unlock();
		}
		try {
			lastKnownSyncer.sync();

		} catch (final Exception e) {
			e.printStackTrace();
		}
	}


	public ArrayList<ItemVersion<IDT,IT>> getAllSyncPending() {
		try {
			dbhandle.lock();

			return dbhandle.getAllPending();
		} finally {
			dbhandle.unlock();
		}
	}

	public ArrayList<ItemVersion<IDT,IT>> getAllSynced() {
		try {
			dbhandle.lock();
			return dbhandle.getAllSynced();
		} finally {
			dbhandle.unlock();
		}
	}

	/**
	 * 
	 */
	public void sync() {
		try {
			lastKnownSyncer.sync();
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @param eventID
	 */
	public void initiateRemove(final IDT id) {
		try {
			dbhandle.lock();
			Long oldVersion = dbhandle.getVersion(id);
			if (oldVersion==null) 
				dbhandle.addChangePending(id,null,0);
			else {
				dbhandle.addChangePending(id,null,++oldVersion);
			}
		} finally {
			dbhandle.unlock();
		}
		try {
			lastKnownSyncer.sync();

		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return dbhandle.toString();
	}

	public boolean addDistributedDatabaseListener(final DistributedDatabaseListener<IDT, IT> l) {
		return dbhandle.addDistributedDatabaseListener(l);
	}

	public boolean removeDistributedDatabaseListener(final DistributedDatabaseListener<IDT, IT> l) {
		return dbhandle.removeDistributedDatabaseListener(l);
	}



}
